Full-Stack

Welcome Portfolio Projects Contact
↑ Go Back ↑

LXC Setup on Arch Linux

LXC Setup on Arch Linux

Info

This setup is for UNPRIVILEGED containers running directly under the user. This is the most secure way to run LXC containers, because the root account is not directly involved.

Install LXC

Taken from https://wiki.archlinux.org/title/Linux_Containers#Required_software

sudo pacman -Syu lxc arch-install-scripts

Create usernet file in home

Taken from: https://linuxcontainers.org/lxc/getting-started/

echo "$(id -un) veth lxcbr0 10" | sudo tee -a /etc/lxc/lxc-usernet

Create UID config in home directory

Taken from https://linuxcontainers.org/lxc/getting-started/

mkdir ~/.config/lxc
cp /etc/lxc/default.conf ~/.config/lxc/default.conf
sudo nano ~/.config/lxc/default.conf

and append the following lines:

  • lxc.idmap = u 0 100000 65536
  • lxc.idmap = g 0 100000 65536 These values have to match those found in /etc/subuid and /etc/subgid. In Arch, these should already be set correctly.

Fix UID permissions of home directory

This fixes the 'Permission denied - Could not access /home/. Please grant it x access, or add an ACL for the container root' error on startup:

setfacl -m u:100000:x /home/<username>

Enable LXC Bridge (no internet)

There are two options here. If you don't neet network, you can follow these steps.

Since the file under /etc/default/lxc-net does not exist, we set the usage of the LXC bridge to true here:

sudo nano /etc/default/lxc

USE_LXC_BRIDGE="true"  # overridden in lxc-net

And restart the lxc-net service to start and enable the LXC bridge:

sudo systemctl start lxc-net
sudo systemctl enable lxc-net

Enable LXC Bridge (with internet)

Taken from: https://wiki.archlinux.org/title/Linux_Containers Create the configuration for the network bridge and fill the relevant info:

sudo nano /etc/default/lxc-net

And fill this:

# Leave USE_LXC_BRIDGE as "true" if you want to use lxcbr0 for your
# containers.  Set to "false" if you'll use virbr0 or another existing
# bridge, or mavlan to your host's NIC.
USE_LXC_BRIDGE="true"

# If you change the LXC_BRIDGE to something other than lxcbr0, then
# you will also need to update your /etc/lxc/default.conf as well as the
# configuration (/var/lib/lxc/<container>/config) for any containers
# already created using the default config to reflect the new bridge
# name.
# If you have the dnsmasq daemon installed, you'll also have to update
# /etc/dnsmasq.d/lxc and restart the system wide dnsmasq daemon.
LXC_BRIDGE="lxcbr0"
LXC_ADDR="10.0.3.1"
LXC_NETMASK="255.255.255.0"
LXC_NETWORK="10.0.3.0/24"
LXC_DHCP_RANGE="10.0.3.31,10.0.3.254"
LXC_DHCP_MAX="253"
# Uncomment the next line if you'd like to use a conf-file for the lxcbr0
# dnsmasq.  For instance, you can use 'dhcp-host=mail1,10.0.3.100' to have
# container 'mail1' always get ip address 10.0.3.100.
#LXC_DHCP_CONFILE=/etc/lxc/dnsmasq.conf

# Uncomment the next line if you want lxcbr0's dnsmasq to resolve the .lxc
# domain.  You can then add "server=/lxc/10.0.3.1' (or your actual $LXC_ADDR)
# to your system dnsmasq configuration file (normally /etc/dnsmasq.conf,
# or /etc/NetworkManager/dnsmasq.d/lxc.conf on systems that use NetworkManager).
# Once these changes are made, restart the lxc-net and network-manager services.
# 'container1.lxc' will then resolve on your host.
#LXC_DOMAIN="lxc"

Additional Info:

  • The default lxcbr0 has an IP range of 10.0.3.2 - 10.0.3.254 defined. We changed it to 10.0.3.31 - 10.0.3.254
  • It makes sense to use 10.0.3.1 as LXC_ADDR if the default or the range above is used
  • By executing sudo systemctl status lxc-net some info about the bridge can be seen

If you are happy with the configuration, (re)start the lxc-net service to start:

sudo systemctl restart lxc-net

Enable the LXC bridge, if it is not already enabled:

sudo systemctl enable lxc-net

Configure fixed container IPv4

If the container doesn't get an IPv4, we can set a fixed IPv4 address to circumvent the issue.

[!NOTE] This step can only be done after the container was created and started.

[!IMPORTANT] The following example is for a Debian container which is using systemd-networkd as a networking service.

While attached to the container, edit the following config:

sudo vi /etc/systemd/network/eth0.network

And instead of using DHCP put a fixed IPv4 in it:

[Match]
Name=eth0

[Network]
#DHCP=true # Disabled because of our fixed IPv4
Address=10.0.3.2/24
Gateway=10.0.3.1
DNS=1.1.1.1

[DHCPv4]
UseDomains=true

[DHCP]
ClientIdentifier=mac

This will collide if another container actually gets an IPv4 and it is the same as the here defined one.

Setup & Run Container

Create Container

systemd-run --unit=my-unit --user --scope -p "Delegate=yes" -- lxc-create --name mycontainer --template download

You can select a distribution, release version and architecture interactively.

If you want to specify the location where the container gets created, use the --lxcpath option. When set, this path has to be passed along all future lxc-* commands for it to find the container. An example to create the container inside the /some/path/lxc-containers folder:

systemd-run --unit=my-unit --user --scope -p "Delegate=yes" -- lxc-create --lxcpath "/some/path/lxc-containers" --name mycontainer --template download

Run Container

To run the container (and attaching via the -F option), run:

systemd-run --unit=my-unit --user --scope -p "Delegate=yes" -- lxc-start -F --lxcpath=/some/path/lxc-containers --name mycontainer

The --lxcpath option can be omitted to use the default container location.

Note that you cannot login here since no password is set out of the box.

Stop container

Stop the container with:

systemd-run --unit=my-unit --user --scope -p "Delegate=yes" -- lxc-stop --lxcpath=/some/path/lxc-containers --name mycontainer

The --lxcpath option can be omitted to use the default container location.

Check container status

For containers in the default location:

lxc-ls --fancy --lxcpath=/some/path/lxc-containers

The --lxcpath option can be omitted to use the default container location.

Delete container

To delete the container:

systemd-run --unit=my-unit --user --scope -p "Delegate=yes" -- lxc-destroy --lxcpath=/some/path/lxc-containers --name mycontainer

The --lxcpath option can be omitted to use the default container location.

Execute code inside container

We cannot login when the container was freshly created, but we can execute commands directly from outside the container.

This executes uname -a inside the LXC container:

lxc-execute --lxcpath=/some/path/lxc-containers --name=mycontainer -- uname -a

The --lxcpath option can be omitted to use the default container location.

Attaching to the container

To further interact with the container, for example to set a username and password, you need to be attached as root to the container. For attaching, you HAVE to start it using the start script above. If you used virt-manager to start it, it doesn't work.

We can do that as follows:

lxc-attach --lxcpath=/some/path/lxc-containers --name=mycontainer

After attaching, create user and set password

Create a user

For some reason, the useradd command is not in the PATH (at least in the debian container template), so we need to execute it with the full path:

/usr/sbin/useradd user

And to change its password:

passwd user

And to add him to the sudoers list:

/usr/sbin/usermod -aG sudo user

Usage after attaching

For some reason, the console when using the -F option is kinda broken.

We can attach (see attaching to container) and then login as our created user:

su - user